﻿using System.Reflection;
using System.Threading.Tasks;

namespace Fast.Reflection
{
    /// <summary>
    /// AspectDispatchProxy 为代理对象的实例化和方法调度的处理提供了一种机制。
    /// </summary>
    [SkipScan]
    public abstract class AspectDispatchProxy
    {
        /// <summary>
        /// 执行同步方法代理。
        /// 每当调用生成的代理类型上的任何方法时，都会调用此方法来控制。
        /// </summary>
        /// <param name="targetMethod">调用者调用的方法</param>
        /// <param name="args">调用者传递给方法的参数</param>
        /// <returns>返回给调用者的对象, 或 <c>null</c> 表示 void 方法</returns>
        protected abstract object Invoke(MethodInfo targetMethod, object[] args);

        /// <summary>
        /// 执行异步方法代理。
        /// 每当调用生成的代理类型上的任何方法时，都会调用此方法来控制。
        /// </summary>
        /// <param name="targetMethod"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        protected abstract Task InvokeAsync(MethodInfo targetMethod, object[] args);

        /// <summary>
        /// 执行异步方法并返回 Task{T} 的代理
        /// 每当调用生成的代理类型上的任何方法时，都会调用此方法来控制。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="targetMethod"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        protected abstract Task<T> InvokeWithResultAsync<T>(MethodInfo targetMethod, object[] args);

        /// <summary>
        /// 创建从 <typeparamref name="TProxy"/> 类派生的对象实例，并实现接口 <typeparamref name="T"/>。 
        /// </summary>
        /// <typeparam name="T">代理应该实现的接口。</typeparam>
        /// <typeparam name="TProxy">用于代理类的基类。</typeparam>
        /// <returns>一个实现 <typeparamref name="T"/> 的对象实例.</returns>
        /// <exception cref="System.ArgumentException"><typeparamref name="T"/> 是一个类,或 <typeparamref name="TProxy"/> 是密封的或没有无参数构造函数的类</exception>
        public static T Create<T, TProxy>() where TProxy : AspectDispatchProxy
        {
            return (T)AspectDispatchProxyGenerator.CreateProxyInstance(typeof(TProxy), typeof(T));
        }
    }
}
